home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / unarced / graphics / anim / iffw.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  9KB  |  260 lines

  1. /*----------------------------------------------------------------------*
  2.  * IFFW.C  Support routines for writing IFF-85 files.          1/23/86
  3.  * (IFF is Interchange Format File.)
  4.  *
  5.  * By Jerry Morrison and Steve Shaw, Electronic Arts.
  6.  * This software is in the public domain.
  7.  *
  8.  * This version for the Commodore-Amiga computer.
  9.  *----------------------------------------------------------------------*/
  10. #include "functions.h"
  11. #include "iff.h"
  12. #include "gio.h"
  13. #include "stdio.h"
  14. /* ---------- IFF Writer -----------------------------------------------*/
  15.  
  16. /* A macro to test if a chunk size is definite, i.e. not szNotYetKnown.*/
  17. #define Known(size)   ( (size) != szNotYetKnown )
  18.  
  19. /* Yet another weird macro to make the source code simpler...*/
  20. #define IfIffp(expr)  {if (iffp == IFF_OKAY)  iffp = (expr);}
  21.  
  22. /* ---------- OpenWIFF -------------------------------------------------*/
  23. #if 0
  24. extern FILE *console;
  25. #endif
  26.  
  27. IFFP OpenWIFF(file, new0, limit)  BPTR file; GroupContext *new0; LONG limit; {
  28.     register GroupContext *new = new0;
  29.     register IFFP iffp = IFF_OKAY;
  30.  
  31.     new->parent       = NULL;
  32.     new->clientFrame  = NULL;
  33.     new->file         = file;
  34.     new->position     = 0;
  35.     new->bound        = limit;
  36.     new->ckHdr.ckID   = NULL_CHUNK;  /* indicates no current chunk */
  37.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  38. #if 0
  39. fprintf(console,"openwiff-1\n");
  40. #endif
  41.  
  42. #if 0
  43.     if (0 > Seek(file, 0L, OFFSET_BEGINNING))    /* Go to start of the file.*/
  44.     iffp = DOS_ERROR;
  45.     else if ( Known(limit) && IS_ODD(limit) )
  46.     iffp = CLIENT_ERROR;
  47. #endif
  48. #if 0
  49. fprintf(console,"openwiff-2: %d\n",iffp);
  50. #endif
  51.     return(iffp);
  52.     }
  53.  
  54. /* ---------- StartWGroup ----------------------------------------------*/
  55. IFFP StartWGroup(parent, groupType, groupSize, subtype, new)
  56.       GroupContext *parent, *new; ID groupType, subtype; LONG groupSize;  {
  57.     register IFFP iffp;
  58.  
  59.     iffp = PutCkHdr(parent, groupType, (long)groupSize);
  60.     IfIffp( IFFWriteBytes(parent, (BYTE *)&subtype, (long)sizeof(ID)) );
  61.     IfIffp( OpenWGroup(parent, new) );
  62.     return(iffp);
  63.     }
  64.  
  65. /* ---------- OpenWGroup -----------------------------------------------*/
  66. IFFP OpenWGroup(parent0, new0)  GroupContext *parent0, *new0; {
  67.     register GroupContext *parent = parent0;
  68.     register GroupContext *new    = new0;
  69.     register LONG ckEnd;
  70.     register IFFP iffp = IFF_OKAY;
  71.  
  72.     new->parent       = parent;
  73.     new->clientFrame  = parent->clientFrame;
  74.     new->file         = parent->file;
  75.     new->position     = parent->position;
  76.     new->bound        = parent->bound;
  77.     new->ckHdr.ckID   = NULL_CHUNK;
  78.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  79.  
  80.     if ( Known(parent->ckHdr.ckSize) ) {
  81.     ckEnd = new->position + ChunkMoreBytes(parent);
  82.     if ( new->bound == szNotYetKnown || new->bound > ckEnd )
  83.         new->bound = ckEnd;
  84.     };
  85.  
  86.     if ( parent->ckHdr.ckID == NULL_CHUNK || /* not currently writing a chunk*/
  87.      IS_ODD(new->position) ||
  88.          (Known(new->bound) && IS_ODD(new->bound)) )
  89.     iffp = CLIENT_ERROR;
  90.     return(iffp);
  91.     }
  92.  
  93. /* ---------- CloseWGroup ----------------------------------------------*/
  94. IFFP CloseWGroup(old0)  GroupContext *old0; {
  95.     register GroupContext *old = old0;
  96.     IFFP iffp = IFF_OKAY;
  97.  
  98.     if ( old->ckHdr.ckID != NULL_CHUNK )  /* didn't close the last chunk */
  99.     iffp = CLIENT_ERROR;
  100.     else if ( old->parent == NULL ) {      /* top level file context */
  101.     if (GWriteFlush(old->file) < 0)  iffp = DOS_ERROR;
  102.     }
  103.     else {                  /* update parent context */
  104.     old->parent->bytesSoFar += old->position - old->parent->position;
  105.     old->parent->position = old->position;
  106.     };
  107.     return(iffp);
  108.     }
  109.  
  110. /* ---------- EndWGroup ------------------------------------------------*/
  111. IFFP EndWGroup(old)  GroupContext *old;  {
  112.     register GroupContext *parent = old->parent;
  113.     register IFFP iffp;
  114.  
  115.     iffp = CloseWGroup(old);
  116.     IfIffp( PutCkEnd(parent) );
  117.     return(iffp);
  118.     }
  119.  
  120. /* ---------- PutCk ----------------------------------------------------*/
  121. IFFP PutCk(context, ckID, ckSize, data)
  122.       GroupContext *context; ID ckID; LONG ckSize; BYTE *data; {
  123.     register IFFP iffp = IFF_OKAY;
  124.  
  125.     if ( ckSize == szNotYetKnown )
  126.     iffp = CLIENT_ERROR;
  127.     IfIffp( PutCkHdr(context, ckID, ckSize) );
  128.     IfIffp( IFFWriteBytes(context, data, ckSize) );
  129.     IfIffp( PutCkEnd(context) );
  130.     return(iffp);
  131.     }
  132.  
  133. /* ---------- PutCkHdr -------------------------------------------------*/
  134. IFFP PutCkHdr(context0, ckID, ckSize)
  135.       GroupContext *context0;  ID ckID;  LONG ckSize; {
  136.     register GroupContext *context = context0;
  137.     LONG minPSize = sizeof(ChunkHeader); /* physical chunk >= minPSize bytes*/
  138.  
  139.     /* CLIENT_ERROR if we're already inside a chunk or asked to write
  140.      * other than one FORM, LIST, or CAT at the top level of a file */
  141.     /* Also, non-positive ID values are illegal and used for error codes.*/
  142.     /* (We could check for other illegal IDs...)*/
  143.     if ( context->ckHdr.ckID != NULL_CHUNK  ||  ckID <= 0 )
  144.     return(CLIENT_ERROR);
  145.     else if (context->parent == NULL)  {
  146.     switch (ckID)  {
  147.         case FORM:  case LIST:  case CAT:  break;
  148.         default: return(CLIENT_ERROR);
  149.         }
  150.     if (context->position != 0)
  151.         return(CLIENT_ERROR);
  152.     }
  153.  
  154.     if ( Known(ckSize) ) {
  155.     if ( ckSize < 0 )
  156.         return(CLIENT_ERROR);
  157.     minPSize += ckSize;
  158.     };
  159.     if ( Known(context->bound)  &&
  160.          context->position + minPSize > context->bound )
  161.     return(CLIENT_ERROR);
  162.  
  163.     context->ckHdr.ckID   = ckID;
  164.     context->ckHdr.ckSize = ckSize;
  165.     context->bytesSoFar   = 0;
  166.     if (0 >
  167.     GWrite(context->file, (BYTE *)&context->ckHdr
  168.                 , (long)sizeof(ChunkHeader))) return(DOS_ERROR);
  169.     context->position += sizeof(ChunkHeader);
  170.     return(IFF_OKAY);
  171.     }
  172.  
  173. /* ---------- IFFWriteBytes ---------------------------------------------*/
  174. IFFP IFFWriteBytes(context0, data, nBytes)
  175.       GroupContext *context0;  BYTE *data;  LONG nBytes; {
  176.     register GroupContext *context = context0;
  177.  
  178.     if ( context->ckHdr.ckID == NULL_CHUNK  ||    /* not in a chunk */
  179.      nBytes < 0  ||                /* negative nBytes */
  180.      (Known(context->bound)  &&        /* overflow context */
  181.         context->position + nBytes > context->bound)  ||
  182.      (Known(context->ckHdr.ckSize)  &&       /* overflow chunk */
  183.         context->bytesSoFar + nBytes > context->ckHdr.ckSize) )
  184.     return(CLIENT_ERROR);
  185.  
  186.     if (0 > GWrite(context->file, data, nBytes))
  187.     return(DOS_ERROR);
  188.  
  189.     context->bytesSoFar += nBytes;
  190.     context->position   += nBytes;
  191.     return(IFF_OKAY);
  192.     }
  193.  
  194. /* ---------- PutCkEnd -------------------------------------------------*/
  195. IFFP PutCkEnd(context0)  GroupContext *context0; {
  196.     register GroupContext *context = context0;
  197.     WORD zero = 0;    /* padding source */
  198.     long temp;
  199.  
  200.     if ( context->ckHdr.ckID == NULL_CHUNK )  /* not in a chunk */
  201.     return(CLIENT_ERROR);
  202.  
  203.     if ( context->ckHdr.ckSize == szNotYetKnown ) {
  204.     /* go back and set the chunk size to bytesSoFar */
  205.     if ( 0 >
  206. GSeek(context->file, (-((long)context->bytesSoFar + (long)sizeof(LONG)))
  207.                       , (long)OFFSET_CURRENT) ||
  208.          0 >
  209. GWrite(context->file, (BYTE *)&context->bytesSoFar, (long)sizeof(LONG))  ||
  210.          0 >
  211. GSeek(context->file, (long)context->bytesSoFar, (long)OFFSET_CURRENT)  )
  212.         return(DOS_ERROR);
  213.     }
  214. #if 0
  215.         temp = - ((long)context->bytesSoFar + (long)sizeof(LONG));
  216.         printf("gseek: %ld %ld %ld %ld\n",temp
  217.                                      ,(long)context->bytesSoFar
  218.                                      ,(long)sizeof(LONG)
  219.                                      ,(long)OFFSET_CURRENT);
  220.     if ( 0 > GSeek(context->file,temp
  221.                       , (long)OFFSET_CURRENT)) {
  222.            printf("putckend 1:\n");
  223.            return(DOS_ERROR);
  224.         }
  225.     if ( 0 > GWrite(context->file
  226.                  , (BYTE *)&context->bytesSoFar
  227.                  , (long)sizeof(LONG))) {
  228.            printf("putckend 2:\n");
  229.            return(DOS_ERROR);
  230.         }
  231.     if ( 0 > GSeek(context->file
  232.                     , (long)context->bytesSoFar
  233.                     , (long)OFFSET_CURRENT)  ) {
  234.            printf("putckend 3:\n");
  235.            return(DOS_ERROR);
  236.     }
  237.     }
  238. #endif
  239.     else {  /* make sure the client wrote as many bytes as planned */
  240.     if ( context->ckHdr.ckSize != context->bytesSoFar )
  241.         return(CLIENT_ERROR);
  242.     };
  243.  
  244.     /* Write a pad byte if needed to bring us up to an even boundary.
  245.      * Since the context end must be even, and since we haven't
  246.      * overwritten the context, if we're on an odd position there must
  247.      * be room for a pad byte. */
  248.     if ( IS_ODD(context->bytesSoFar) ) {
  249.     if ( 0 > GWrite(context->file, (BYTE *)&zero, 1L) ) {
  250.            return(DOS_ERROR);
  251.         }
  252.     context->position += 1;
  253.     };
  254.  
  255.     context->ckHdr.ckID   = NULL_CHUNK;
  256.     context->ckHdr.ckSize = context->bytesSoFar = 0;
  257.     return(IFF_OKAY);
  258.     }
  259.  
  260.